using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Windows.Forms;
using System.Drawing;

namespace TgcViewer.Utils
{
    public class TgcD3dDevice
    {
        private Device d3dDevice = null;
        /// <summary>
        /// Direct3D Device
        /// </summary>
        public Device D3dDevice
        {
            get { return d3dDevice; }
        }

        Control panel3d;
        readonly Color CLEAR_COLOR = Color.FromArgb(255, 78, 129, 179);
        public static readonly Material DEFAULT_MATERIAL = new Material();

        public TgcD3dDevice(Control panel3d)
        {
            this.panel3d = panel3d;

            Caps caps = Manager.GetDeviceCaps(Manager.Adapters.Default.Adapter, DeviceType.Hardware);
            CreateFlags flags;

            if (caps.DeviceCaps.SupportsHardwareTransformAndLight)
                flags = CreateFlags.HardwareVertexProcessing;
            else
                flags = CreateFlags.SoftwareVertexProcessing;

            PresentParameters d3dpp = new PresentParameters();

            d3dpp.BackBufferFormat = Format.Unknown;
            d3dpp.SwapEffect = SwapEffect.Discard;
            d3dpp.Windowed = true;
            d3dpp.EnableAutoDepthStencil = true;
            d3dpp.AutoDepthStencilFormat = DepthFormat.D16;
            d3dpp.PresentationInterval = PresentInterval.Immediate;
            
            //Antialiasing
            if (Manager.CheckDeviceMultiSampleType(Manager.Adapters.Default.Adapter, DeviceType.Hardware,
                Manager.Adapters.Default.CurrentDisplayMode.Format, true, MultiSampleType.NonMaskable))
            {
                d3dpp.MultiSample = MultiSampleType.NonMaskable;
                d3dpp.MultiSampleQuality = 0;
            }
            else
            {
                d3dpp.MultiSample = MultiSampleType.None;
            }
            

            //Crear Graphics Device
            d3dDevice = new Device(0, DeviceType.Hardware, panel3d, flags, d3dpp);
            d3dDevice.DeviceReset += new System.EventHandler(this.OnResetDevice);
        }

        /// <summary>
        /// This event-handler is a good place to create and initialize any 
        /// Direct3D related objects, which may become invalid during a 
        /// device reset.
        /// </summary>
        public void OnResetDevice(object sender, EventArgs e)
        {
            GuiController.Instance.onResetDevice();
        }

        /// <summary>
        /// Hace las operaciones de Reset del device
        /// </summary>
        internal void doResetDevice()
        {
            setDefaultValues();

            //Reset Timer
            HighResolutionTimer.Instance.Reset();
        }

        /// <summary>
        /// Valores default del Direct3d Device
        /// </summary>
        internal void setDefaultValues()
        {
            //Frustum values
            d3dDevice.Transform.Projection =
                Matrix.PerspectiveFovLH(Geometry.DegreeToRadian(45.0f),
                (float)this.panel3d.Width / this.panel3d.Height,
                1f, 2000f);

            //Render state
            d3dDevice.RenderState.Lighting = false;
            d3dDevice.RenderState.FillMode = FillMode.Solid;
            d3dDevice.RenderState.CullMode = Cull.None;
            d3dDevice.RenderState.MultiSampleAntiAlias = true;
            d3dDevice.RenderState.SlopeScaleDepthBias = -0.1f;
            d3dDevice.RenderState.DepthBias = 0f;

            //Texture Filtering
            d3dDevice.SetSamplerState(0, SamplerStageStates.MinFilter, (int)TextureFilter.Linear);
            d3dDevice.SetSamplerState(0, SamplerStageStates.MagFilter, (int)TextureFilter.Linear);
            d3dDevice.SetSamplerState(0, SamplerStageStates.MipFilter, (int)TextureFilter.Linear);

            d3dDevice.SetSamplerState(1, SamplerStageStates.MinFilter, (int)TextureFilter.Linear);
            d3dDevice.SetSamplerState(1, SamplerStageStates.MagFilter, (int)TextureFilter.Linear);
            d3dDevice.SetSamplerState(1, SamplerStageStates.MipFilter, (int)TextureFilter.Linear);

            //Clear lights
            foreach (Light light in d3dDevice.Lights)
            {
                light.Enabled = false;
            }

            //Limpiar todas las texturas
            for (int i = 0; i < 8; i++)
			{
                d3dDevice.SetTexture(i, null);
			}

            //Reset Material
            d3dDevice.Material = DEFAULT_MATERIAL;
            
        }

        internal void doClear()
        {
            d3dDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer, CLEAR_COLOR, 1.0f, 0);
            HighResolutionTimer.Instance.Set();
        }

        internal void resetWorldTransofrm()
        {
            d3dDevice.Transform.World = Matrix.Identity;
        }
    }
}
